package nz.ac.massey.groupproject.ecs2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;


public class ECSQueryTemplate {

	private static final HashMap<ECSQueryTemplate, ECSQueryTemplate>   instances   = new HashMap<>();

	// The same compTypes should reuse the same instance.
	public static ECSQueryTemplate get(Class... compTypes) {
		var newInstance = new ECSQueryTemplate(compTypes);
		instances.putIfAbsent(newInstance, newInstance);
		return instances.get(newInstance);
	}
	public static ECSQueryTemplate get(ArrayList<Class> compTypes) {
		return get( compTypes.toArray(new Class[]{}) );
	}










	// TODO sanity check: requiredCompTs does not contain duplicates
	Class[]             requiredCompTs;    // TODO make this private and implement getRelevantComponentTypes()

	private ECSQueryTemplate(Class... compTypes) {
		assert areValidCompTypes(compTypes) : "Attempting to create an ECSQueryTemplate on non-component types";
		requiredCompTs = compTypes;
	}

	private static final boolean areValidCompTypes(Class[] compTypes) {
		for (var cls : compTypes)
			if (! ECSComponent.class.isAssignableFrom(cls))
				return false;
		return true;
	}

	public int hashCode() {
		return 0;             // FIXME improve performance
	}

	public boolean equals(Object obj) {
		if (!(obj instanceof ECSQueryTemplate)) return false;
		var t2 = (ECSQueryTemplate) obj;

		if (getClass() != t2.getClass()) return false;   // This is no-op for now, but we plan to implement polymorphic queries later

		if (requiredCompTs.length != t2.requiredCompTs.length) return false;

		var myTypes = new HashSet<Class>();
		for (var cls : requiredCompTs)
			myTypes.add(cls);
		for (var cls : t2.requiredCompTs)
			if (! myTypes.contains(cls))
				return false;
		return true;
	}




	public ECSQuery create(ECSWorld world) {
		return new ECSQuery(world, this);
	}




	public boolean matchEntity(ECSEntity ent) {
		for (var cls : requiredCompTs)
			if (! ent.hasComponent(cls))
				return false;
		return true;
	}

}
